<!doctype html>
<html lang="zh-CN">

	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
		<title>多对多</title>
		<script src="js/jquery-3.2.1.js" type="text/javascript" charset="utf-8"></script>
		<style type="text/css">
		
		</style>
	</head>

	<body>
		<p>复选框之间多对多的父子关系</p>
		<input type="checkbox" issued="歌手|演员" /><label>全部</label>
		<br />
		<input type="checkbox" issued="歌手" /><label>歌手</label>
		<input type="checkbox" issued="演员" /><label>演员</label>
		<br />
		<input type="checkbox" issued="男&歌手" /><label>男歌手</label>
		<input type="checkbox" issued="女&歌手" /><label>女歌手</label>
		<input type="checkbox" issued="男&演员" /><label>男演员</label>
		<input type="checkbox" issued="女&演员" /><label>女演员</label>
		<br />
		<input type="checkbox" report="歌手 演员 男" /><label>刘德华</label>
		<input type="checkbox" report="歌手 男" /><label>周杰伦</label>
		<input type="checkbox" report="演员 女" /><label>刘亦菲</label>
		<input type="checkbox" report="歌手 演员 男" /><label>张学友</label>
		<input type="checkbox" report="歌手 女" /><label></label>
		<input type="checkbox" report="歌手 女" /><label>刘德华</label>


		<script type="text/javascript">
			function getIssued(issued) {
				issued = (function(infixNotation) { //转换为逆波兰表达式
					infixNotation = infixNotation.replace(' ', '').match(/&|\||\(|\)|!|([^&\|()!]+)/g);
					var s1 = [], //结果栈
						s2 = []; //运算符栈
					infixNotation.forEach(function(v) {
						if(v === "(") { //遇到左括号直接加入运算符栈
							s2.push(v);
						} else if(v === ')') {
							while(s2.length && s2[s2.length - 1] !== '(') {
								//遇到')' 循环取运算符栈顶加入结果栈
								s1.push(s2.pop());
							};
							s2.pop(); //移除栈顶的'('
						} else if(v === '&' || v === '|' || v === '!') {
							while(s2.length && (s2[s2.length - 1] === '!')) {
								//遇到运算符且该运算符优先级大于等于运算符栈顶，循环取运算符栈顶加入结果栈，直到不满足条件
								s1.push(s2.pop());
							};
							s2.push(v); //最后把当前运算符加入运算符栈
						} else {
							s1.push(v); //其他类型直接加入结果栈
						};

					});
					while(s2.length) {
						s1.push(s2.pop()); //最后循环将运算符栈加入结果栈
					};
					return s1;
				})(issued);
				var all = $('input[report]');
				var re = [];
				issued.forEach(function(v) { //根据表达式筛选结果
					if(v === '!') {
						re.push(all.not(re.pop()));
					} else if(v === '&') {
						re.push(re.pop().filter(re.pop()));
					} else if(v === '|') {
						re.push(re.pop().add(re.pop()));
					} else {
						//						if(v === 'all') {
						//							re.push(all);
						//						} else {
						re.push(all.filter('[report*=' + v + ']'));
						//						}
					};
				});
				return re[0];
			};

			$('input[issued]:checkbox').on('change', function(event) {
				$(this).trigger('issued');
				//				$(this).trigger('upState');
			}).on('issued', function(event) {
				getIssued($(this).attr('issued'))
					.prop('checked', this.checked)
					.trigger('change')
					.filter('[issued]')
					.prop('indeterminate', false)
//					.trigger('issued');
			}).on('upState', function() {
				var all = getIssued($(this).attr('issued'));
				var all_checked = all.filter(':checked');
				var all_indeterminate = all.map(function() {
					return this.indeterminate ? this : null;
				});
				$(this).prop('checked', all_checked.length)
					.prop('indeterminate', all_indeterminate.length || all_checked.length !== 0 && all_checked.length !== all.length);
			});
			
			$('input[report]:checkbox').on('change', function(event) {
//				$(this).trigger('report');
				$('input[issued]').trigger('upState');
				
			}).on('report', function(event) {
				console.log(123);


				//				
				//				$('input[issued]').each(function(i,v) {
				//					var is = getIssued($(this).attr('issued'))
				////					console.log($(this).attr('issued'), is);
				//				})
				//
				//				var report = $(this).attr('report').split(' ');
				//				return;
				//
				//				var reportInput = $('input[report=' + report + ']');
				//				var reportInput_checked = reportInput.filter(':checked');
				//				var reportInput_indeterminate = reportInput.map(function() {
				//					return this.indeterminate ? this : null;
				//				});
				//				var issued = $('input[issued=' + report + ']');
				//				issued.prop('checked', reportInput_checked.length)
				//					.prop('indeterminate', reportInput_indeterminate.length || reportInput_checked.length !== 0 && reportInput_checked.length !== reportInput.length)
				//					.filter('[report]')
				//					.trigger('report');
			});
		</script>
		<script type="text/javascript">
		</script>

	</body>

</html>